package tools.illumina;

import java.io.BufferedWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

import tools.fastq.FastqSeq;

public class clonalityChecker {

	private int minLength,endCluster;
	private HashMap<String, ArrayList<ClonalityItem>> store;
	private ArrayList<ClonalityItem> tmpAL;
	private boolean added;
	
	public clonalityChecker(int minLength){
		this.minLength=minLength;
		this.store= new HashMap<String, ArrayList<ClonalityItem>>();
	}
	
	public void add(FastqSeq fqs){
		final String key=fqs.getSeq().substring(0, minLength);
		if(store.containsKey(key)){
			added=false;
			tmpAL= store.get(key);
			for (ClonalityItem ci : tmpAL) {
				added=ci.add(fqs);
				if(added){
					break;
				}
			}
			if(!added){
				tmpAL.add(new ClonalityItem(fqs));
			}
		}else{
			tmpAL= new ArrayList<ClonalityItem>();
			tmpAL.add(new ClonalityItem(fqs));
			store.put(key, tmpAL);
		}
	}
	
	public void postPooling(){
		for (String key : store.keySet()) {
			store.put(key, this.pool(store.get(key)));
		}
	}
	
	public ArrayList<String> outList(int start) throws Exception{
		ArrayList<String> list= new ArrayList<String>();
		int cluster=start;
		for (String key : store.keySet()) {
			for (ClonalityItem ci : store.get(key)) {
				cluster++;
				list.addAll(ci.outList(cluster+""));
			}
		}
		endCluster=cluster;
		return list;
	}
	
	//should only be called after outList
	public int getEndCluster(){
		return endCluster;
	}
	
	public void print(BufferedWriter out)throws Exception{
		int cluster=0;
		for (String key : store.keySet()) {
			for (ClonalityItem ci : store.get(key)) {
				cluster++;
				ci.print(out, cluster+"");
			}
		}
	}
	
	private ArrayList<ClonalityItem> pool(ArrayList<ClonalityItem> in){
		ArrayList<ClonalityItem> out= new ArrayList<ClonalityItem>();
		//merge
		Collections.sort(in);
		ClonalityItem ci;
		for(;in.size()>0;){
			ci=in.remove(in.size()-1);
			for(int i=in.size()-1;i>-1;i--){
				//try to add a whole set
				if(ci.addWholeClonalityItem(in.get(i))){
					//the ClonalityItem at this index was added and will be removed from the input set.
					in.remove(i);
				}
			}
			out.add(ci);
		}
		//shorter entities can belong to multiple ClonalityItems
		for(int i=0;i<out.size();i++){
			ci=out.get(i);
			for(int j=0;j<out.size();j++){
				if(i!=j){
					ci.addValidSubset(out.get(j));
				}
			}
		}
		return out;
	}
}
